package com.theaf.basemodule.service.impl;

import com.theaf.basemodule.common.condition.ResourceCondition;
import com.theaf.basemodule.common.dto.resource.ResourceDTO;
import com.theaf.basemodule.common.dto.resource.AppDTO;
import com.theaf.basemodule.common.dto.resource.AuthDTO;
import com.theaf.basemodule.common.model.SysResource;
import com.theaf.basemodule.common.vo.resource.ResourceVO;
import com.theaf.basemodule.dao.PositionDAO;
import com.theaf.basemodule.dao.ResourceDAO;
import com.theaf.basemodule.common.api.ResourceService;
import com.theaf.basemodule.dao.UserDAO;
import com.theaf.core.cache.CachesHelper;
import com.theaf.core.cache.RedisHelper;
import com.theaf.core.repo.kit.SimpleSortBuilder;
import com.theaf.core.repo.specification.SqlBuilder;
import com.theaf.core.repo.specification.SqlOperator;
import com.theaf.core.repo.specification.SqlValue;
import com.theaf.core.utils.BeanMapper;
import com.theaf.core.utils.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @Author:songwenke
 * @Description:资源服务
 * @Date:create in 17:03 2018/1/3
 * @Modified By:
 **/
@Service
public class ResourceServiceImpl implements ResourceService{
    @Resource
    private ResourceDAO resourceDAO;

    @Resource
    private PositionDAO positionDAO;

    @Resource
    private UserDAO userDAO;

    private final String CACHE_ALL_SOURCSE = "ALL_SYS_SOURCSE";

    @Override
    public void delete(Long id){
        SysResource sysResource = resourceDAO.findOne(id);
        //删除岗位对应的功能
        positionDAO.deleteResource(id);
        //删除用户对应的功能
        userDAO.deleteResource(id);
        if(sysResource.getType()!=SysResource.TYPE_FUN){
            if(sysResource.getType()==SysResource.TYPE_SYSTEM) {
                //删除系统对应的资源
                resourceDAO.deleteCustom(SqlBuilder.start("sysResource.sysResource.id", id));
            }
            //删除系统对应的模块
            resourceDAO.deleteCustom(SqlBuilder.start("sysResource.id", id));
        }
        resourceDAO.delete(id);
        RedisHelper.clearByPrefix(CACHE_ALL_SOURCSE);
    }

    @Override
    public List<AppDTO> findAllApp() {
        List<SysResource> resources = resourceDAO.findAll(
                SqlBuilder.start("type",SysResource.TYPE_SYSTEM).and("enable",true).gen(),SimpleSortBuilder.generateSort("name"));
        return resources.parallelStream().map(
                n-> BeanMapper.map(n,AppDTO.class)).collect(Collectors.toList());
    }

    @Override
    public List<ResourceDTO> findList(ResourceCondition condition) {
        SqlBuilder sqlbuilder = new SqlBuilder();
        if(StringUtils.isNotEmpty(condition.getName())||StringUtils.isNotEmpty(condition.getCode())) {
            sqlbuilder.and(resourceDAO.subquery(
                    SqlBuilder.start("name", SqlOperator.OPER.LIKE, SqlValue.parse(condition.getName()))
                            .and("code",SqlOperator.OPER.LIKE, SqlValue.parse(condition.getCode()))
                            .and("levelCode", SqlOperator.OPER.LIKER,"@levelCode")
                            .setSelects(new String[]{"levelCode"})), SqlOperator.OPER.EXISTS, null);
        }
        if(condition.getAppId()!=null){
            sqlbuilder.and("levelCode",SqlOperator.OPER.LIKER,resourceDAO.subquery(
                    SqlBuilder.start("id",condition.getAppId()).setSelects(new String[]{"levelCode"})));
        }
        if(!condition.isIncludeFun()){
            sqlbuilder.and("type", SqlOperator.OPER.NE,3);
        }
        List<SysResource> resources = resourceDAO.findAll(sqlbuilder.gen(), SimpleSortBuilder.generateSort("name"));
        return resources.parallelStream().map(
                n-> ResourceDTO.fromPo(n)).collect(Collectors.toList());
    }

    @Override
    public ResourceDTO findById(Long id) {
        return ResourceDTO.fromPo(resourceDAO.findOne(id));
    }

    @Override
    public long save(ResourceVO vo) {
        SysResource po = resourceDAO.findByIdNewIfisNull(vo.getId());
        BeanMapper.copy(vo, po);
        if(vo.getPid()!=null){
            po.setSysResource(resourceDAO.findOne(vo.getPid()));
        }
        if (po.getId() == null) {
            resourceDAO.initLevel(po, "levelCode","id", "sysResource.id");
        }
        if(po.getEnable()==null) {
            po.setEnable(true);
        }
        resourceDAO.save(po);
        if(vo.getChildren()!=null) {
            for (ResourceVO child : vo.getChildren()) {
                child.setPid(po.getId());
                this.save(child);
            }
        }
        CachesHelper.clearByPrefix(CACHE_ALL_SOURCSE);
        return po.getId();
    }

    @Override
    public List<AuthDTO> findAuths(long appId) {
        List<Object[]> objs = resourceDAO.findAuthByApp(appId);
        AuthDTO pre = null;
        List<AuthDTO> rets = new ArrayList();
        for(Object[] array:objs){
            String moduleName = (String)array[0];
            long funId = (Long)array[1];
            String funName = (String)array[2];
            if(pre == null||!moduleName.equals(pre.getModuelName())){
                pre = new AuthDTO();
                pre.setModuelName(moduleName);
                pre.setFuns(new ArrayList());
                pre.getFuns().add(pre.new FunDTO(funId,funName));
                rets.add(pre);
            }else{
                pre.getFuns().add(pre.new FunDTO(funId,funName));
            }
        }
        return rets;
    }

    @Override
    public Map<Long, Boolean> findAuthMapByPos(long posId) {
        Map<Long, Boolean> map = new HashMap();
        List<ResourceDTO> allRes = findAllResource();
        List<Long> posRes = resourceDAO.findPosFun(posId);
        allRes.forEach(n->{
            map.put(n.getId(),posRes.contains(n.getId()));
        });
        return map;
    }

    @Override
    public List<Long> findAuthsByUser(long userId) {
        return resourceDAO.findUserFun(userId);
    }

    private List<ResourceDTO> findAllResource(){
        List<ResourceDTO> res = (List<ResourceDTO>)CachesHelper.get(CACHE_ALL_SOURCSE);
        if(res==null){
            res = (List<ResourceDTO>)resourceDAO.findAll(
                    SqlBuilder.start("enable",true).gen()).parallelStream().map(
                    n->ResourceDTO.fromPo((SysResource) n)).collect(Collectors.toList());
            CachesHelper.set(CACHE_ALL_SOURCSE,
                    res);
        }
        return res;
    }

    @Override
    public Map<Long, Boolean> findAuthMapByUser(long userId) {
        Map<Long, Boolean> map = new HashMap();
        List<ResourceDTO> allRes = findAllResource();
        List<Long> userRes = findAuthsByUser(userId);
        allRes.forEach(n->{
            map.put(n.getId(),userRes.contains(n.getId()));
        });
        return map;
    }

    @Override
    public List<Long> findDefaultAuthsByUser(long userId) {
        return resourceDAO.findUserFunAddDefaultFun(userId);
    }
}
